using System;
using System.Collections.Generic;
using UnityEngine;

namespace CGF
{
    //Uinty可配合 RectLayoutGroup 或者 GridLayoutGroup 使用
    public class PrizeCard : MonoBehaviour
    {
        class Cell
        {
            public int index;
            public float delay;
        }

        [Header("总格数")]
        public int cellCount;
        [Header("加速的格数")]
        public int acceCellCount = 10;
        [Header("匀速的圈数")]
        public int uniformSpeedRoundCount = 5;
        [Header("减速的圈数")]
        public int deceRoundCount = 2;
        [Header("跳格的最短时间间隔")]
        public float minInterval = 0.03f;
        [Header("跳格的最长时间间隔")]
        public float maxInterval = 0.5f;
        [Header("跳格音效")]
        public AudioClip jumpSound;

        public bool isRunning { get; private set; }
        private List<Cell> cellList = new List<Cell>();
        private Action<int, bool> cellUpdateAction;
        private CTask task;

        private float EaseExpoIn(double t, double b, double c, double d)
        {
            if (t == 0)
            {
                return (float)b;
            }
            else
            {
                return (float)(c * Math.Pow(2, 10 * (t / d - 1)) + b);
            }
        }

        private float EaseExpoOut(double t, double b, double c, double d)
        {
            if (t == d)
            {
                return (float)(b + c);
            }
            else
            {
                return (float)(c * (-Math.Pow(2, -10 * t / d) + 1) + b);
            }
        }


        #region 对外方法///////////////////////////////////////////////////////////////////////


        /// <summary>
        /// 开始旋转，Action<index, isStoped>
        /// </summary>
        /// <param name="startIndex">起始索引</param>
        /// <param name="stopIndex">停止的索引</param>
        /// <param name="onCellUpdate">回调绑在Cell上的组件和跑到的Cell索引【参数：(int index, bool isStoped)】</param>
        /// <param name="ignoreList">排除掉的索引数组，没有可传null</param>
        public void StartRun(int startIndex, int stopIndex, Action<int, bool> onCellUpdate, int[] ignoreList = null)
        {
            StartRunCoroutin(startIndex, stopIndex, onCellUpdate, ignoreList);
        }

        private async void StartRunCoroutin(int startIndex, int stopIndex, Action<int, bool> onCellUpdate, int[] ignoreList = null)
        {
            if (isRunning) return;

            task = CTask.Create();

            this.cellUpdateAction = (int index, bool isStoped) =>
            {
                onCellUpdate?.Invoke(index, isStoped);
            };

            isRunning = true;

            int allDeceCellsCount = 0;
            if (startIndex < stopIndex)
            {
                allDeceCellsCount = cellCount * deceRoundCount + (stopIndex - startIndex) + 1;
            }
            else
            {
                allDeceCellsCount = cellCount * deceRoundCount + (cellCount - startIndex + stopIndex) + 1;
            }
            int totalValidCells = allDeceCellsCount;
            int cellTransIndex = 0;
            for (int i = 0; i < allDeceCellsCount; i++)
            {
                if (IsIgnore(cellTransIndex, ignoreList)) totalValidCells--;
                cellTransIndex++;
                if (cellTransIndex > cellCount - 1) cellTransIndex = 0;
            }
            cellTransIndex = startIndex;

            cellList.Clear();

            //加速几帧之后匀速
            float startInterval = 0.2f;
            int count = cellCount * uniformSpeedRoundCount;
            for (int i = 0; i < count; i++)
            {
                if (!IsIgnore(cellTransIndex, ignoreList))
                {
                    Cell cell = new Cell();
                    cell.index = cellTransIndex;
                    if (i <= acceCellCount)
                    {
                        cell.delay = EaseExpoOut(i, startInterval, minInterval - startInterval, acceCellCount);
                    }
                    else
                    {
                        cell.delay = minInterval;
                    }
                    cellList.Add(cell);
                }
                cellTransIndex++;
                if (cellTransIndex > cellCount - 1) cellTransIndex = 0;
            }

            //减速
            int index = 0;
            for (int i = 0; i < allDeceCellsCount; i++)
            {
                if (!IsIgnore(cellTransIndex, ignoreList))
                {
                    Cell cell = new Cell();
                    cell.index = cellTransIndex;
                    cell.delay = EaseExpoIn(index, minInterval, maxInterval - minInterval, totalValidCells);
                    cellList.Add(cell);
                    index++;
                }
                cellTransIndex++;
                if (cellTransIndex > cellCount - 1) cellTransIndex = 0;
            }
            for (int i = 0; i < cellList.Count; i++)
            {
                Cell cell = cellList[i];
                await CTask.Wait(cell.delay);
                if (!gameObject)
                {
                    task.Dispose();
                    return;
                }
                if (!isRunning)
                {
                    task.Dispose();
                    return;
                }
                bool isStoped = i == cellList.Count - 1;
                SoundPlayer.Play(jumpSound);
                this.cellUpdateAction?.Invoke(cell.index, isStoped);
                if (isStoped)
                {
                    isRunning = false;
                }
            }
            task.Dispose();
        }

        public bool IsIgnore(int index, int[] ignoreList)
        {
            if (ignoreList == null) return false;
            for (int i = 0; i < ignoreList.Length; i++)
            {
                if (index == ignoreList[i])
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 不等转完，立即停止
        /// </summary>
        public void Stop()
        {
            isRunning = false;
        }

        #endregion

    }
}